<?php
/**
 * Created by PhpStorm.
 * User: 我想有个家
 * Date: 2020/4/7
 * Time: 13:52
 */

namespace App\Controller\v1;

use App\Controller\Base;
use App\Lib\AES128;
use App\Lib\Redis;
use App\Lib\Token;
use App\Model\User;
use App\Service\OssService;
use App\Service\SmsService;
use App\Service\QQAuthLogin;
use App\Service\WechatAuthLogin;
use App\Validate\UserValidate;
use Hyperf\Di\Annotation\Inject;
use Hyperf\HttpServer\Annotation\Controller;
use Hyperf\HttpServer\Annotation\Middleware;
use Hyperf\HttpServer\Annotation\RequestMapping;

/**
 * @Controller(prefix="v1")
 * Class Login
 * @package App\Controller
 */
class AuthController extends Base {
    /**
     * @Inject()
     * @var Token
     */
    private $token;

    /**
     * 登录
     * @Middleware(\App\Middleware\NormalMiddleware::class)
     * @RequestMapping(path="login",methods="post")
     */
    public function login() {
        $this->validate(UserValidate::class, 'login');
        $t = trim($this->body('t'));
        switch ($t) {
            case 'wx':
                return $this->loginByWechat();
            case 'qq':
                return $this->loginByQQ();
            default:
                return $this->loginByPwd();
        }
    }

    /**
     * 获取auth参数
     * @return string
     */
    private function getAuth() {
        $auth = (string) $this->body('auth');
        return $this->di->get(AES128::class)->decrypt($auth);
    }

    /**
     * 微信登录
     * @return array
     */
    private function loginByWechat() {
        $auth = $this->getAuth();
        if (empty($auth)) {
            return error('参数auth错误');
        }
        try {
            $info = $this->di->get(WechatAuthLogin::class)->getUserInfo($auth);
        } catch (\Exception $e) {
            return error('微信授权异常，请返回重试');
        }
        $res = $this->getUser([['wx_unionid', '=', $info['unionid']]]);
        if ($res) {
            $res['data'] = [
                'reg' => '',
                'data' => $res['data'],
            ];
            return $res;
        }
        // 账号未注册
        $info['t'] = time();
        $info['f'] = 'wx';
        return success(['reg' => $this->getRegToken($info), 'data' => new \stdClass()]);
    }

    /**
     * QQ登录
     * @return array
     */
    private function loginByQQ() {
        $auth = $this->getAuth();
        if (empty($auth)) {
            return error('参数auth错误');
        }
        $data = json_decode($auth, true);
        if (!isset($data['access_token']) || !isset($data['openid'])) {
            return error('参数auth错误');
        }
        try {
            $info = $this->di->get(QQAuthLogin::class)->getUserInfo($data);
        } catch (\Exception $e) {
            return error('QQ授权异常，请返回重试');
        }
        unset($data);
        $res = $this->getUser([['qq_unionid', '=', $info['unionid']]]);
        if ($res) {
            $res['data'] = [
                'reg' => '',
                'data' => $res['data'],
            ];
            return $res;
        }
        // 账号未注册
        $info['t'] = time();
        $info['f'] = 'qq';
        return success(['reg' => $this->getRegToken($info), 'data' => new \stdClass()]);
    }

    /**
     * @param array $array
     * @return string
     */
    private function getRegToken(array $array) {
        return $this->di->get(AES128::class)->encrypt(json_encode($array, JSON_UNESCAPED_UNICODE));
    }

    /**
     * 第三方登录查询用户信息
     * @param array $condition
     * @return array
     */
    private function getUser(array $condition) {
        /**
         * @var User $user
         */
        $user = User::query()
            ->where($condition)
            ->select('id', 'status')
            ->first();
        if (empty($user)) {
            return [];
        }
        return $this->userStatusCheck($user);
    }

    /**
     * 手机号码 密码登录
     * @return array
     */
    private function loginByPwd() {
        $mobile = $this->body('mobile');
        $pwd = $this->body('pwd');
        if (empty($mobile) || empty($pwd)) {
            return error('账号或者密码不能为空');
        }
        // 查询
        /**
         * @var User $user
         */
        $user = User::query()
            ->where('mobile', $mobile)
            ->select('id', 'pwd', 'status')
            ->first();
        if (empty($user) || saltMd5($pwd) != $user->pwd) {
            return error('账号或密码错误');
        }
        return $this->userStatusCheck($user);
    }

    /**
     * 用户状态统一校验，token创建
     * @param $user User
     * @return array
     */
    private function userStatusCheck($user) {
        if ($user->status == 1) {
            return error('账号状态异常');
        }
        $token = $this->token->create($user->id);
        return success($token);
    }

    /**
     * 刷新token
     * @Middleware(\App\Middleware\NormalMiddleware::class)
     * @RequestMapping(path="refresh",methods="post")
     */
    public function refresh() {
        $this->validate(UserValidate::class, 'refresh');
        $refrash = (string) $this->body('refresh_token');
        $uid = $this->token->refreshTokenVerify($refrash);
        if (is_numeric($uid)) {
            // 查询用户状态
            $userStatus = User::query()
                ->where('id', $uid)
                ->value('status');
            if ($userStatus == 1) {
                return error('账号状态异常');
            }
            $token = $this->token->create($uid);
            return success($token);
        } else {
            return error('请重新登录', 10001);
        }
    }

    /**
     * 退出登录
     * @Middleware(\App\Middleware\MustMiddleware::class)
     * @RequestMapping(path="logout",methods="get")
     */
    public function out() {
        $uid = $this->request->getAttribute('uid');
        Redis::get()->hDel("token", "{$uid}");
        return success();
    }

    /**
     * 注册
     * @Middleware(\App\Middleware\NormalMiddleware::class)
     * @RequestMapping(path="reg",methods="post")
     * @return array
     */
    public function reg() {
        $this->validate(UserValidate::class, 'reg');
        $mobile = $this->body('mobile');
        $sms_code = $this->body('sms_code');
        $pwd = $this->body('pwd');
        if (!pwdCheck($pwd)) {
            return error('密码必须为6-20位字母数字混合');
        }
        // 短信验证
        $code = $this->di->get(SmsService::class)->verify($mobile, $sms_code);
        if ($code) {
            return error($code);
        }
        // 判断手机号码是否注册
        if (User::mobileUsed($mobile)) {
            return error('该手机号码已经注册');
        }
        $id = User::query()
            ->insertGetId([
                'mobile' => $mobile,
                'pwd' => saltMd5($pwd),
                'nick_name' => "手机用户" . mb_substr($mobile, 7),
            ]);
        if ($id > 0) {
            $token = $this->token->create($id);
            return success($token);
        } else {
            return error('注册失败');
        }
    }

    /**
     * 绑定第三方登录
     * @Middleware(\App\Middleware\NormalMiddleware::class)
     * @RequestMapping(path="bind",methods="post")
     * @return array
     */
    public function bind() {
        $this->validate(UserValidate::class, 'bind');
        $mobile = $this->body('mobile');
        $sms_code = $this->body('sms_code');
        $reg = $this->body('reg');
        // 短信验证
        $code = $this->di->get(SmsService::class)->verify($mobile, $sms_code);
        if ($code) {
            return error($code);
        }
        // 注册授权码验证
        $reg = $this->di->get(AES128::class)->decrypt($reg);
        if (empty($reg)) {
            return error('非法参数');
        }
        $reg = json_encode($reg, true);
        if (empty($reg) || !isset($reg['f'])) {
            return error('非法参数');
        }
        if (time() - $reg['t'] > 1800) {
            return error('授权失效，请返回重新授权');
        }
        // 判断手机号码是否注册
        if (User::mobileUsed($mobile)) {
            return error('该手机号码已经注册');
        }
        // 保存头像到oss
        $use = [
            'mobile' => $mobile,
            'headimg' => $this->di->get(OssService::class)->saveHeaderImg($reg['headimgurl']),
        ];
        switch ($reg['f']) {
            case 'qq':
                $use['nick_name'] = $reg['nickname'] ?: 'QQ用户' . mb_substr($mobile, 7);
                $use['qq_unionid'] = $reg['unionid'];
                break;
            case 'wx':
                $use['nick_name'] = $reg['nickname'] ?: '微信用户' . mb_substr($mobile, 7);
                $use['wx_openid'] = $reg['openid'];
                $use['wx_unionid'] = $reg['unionid'];
                break;
            default:
                return error('暂不支持该平台');
        }
        $id = User::query()->insertGetId($use);
        if ($id > 0) {
            $token = $this->token->create($id);
            return success($token);
        } else {
            return error('绑定失败');
        }
    }
}
